import { defineStore } from 'pinia'
import { ref } from 'vue'
import {
    getDefaultCards,
    getDefaultPlayerCards,
    Player
} from '../utils/card-game.util'
import { shuffle } from 'lodash'

export const useCardGameStore = defineStore('card-game', () => {
    const currentStep = ref(1)
    const maxStep = 4
    const maxPlayers = 4

    const winner = ref(-1)

    const players = ref(getDefaultPlayerCards())

    const cards = ref<string[]>(getDefaultCards())

    const increaseStep = () => {
        if (currentStep.value === 1) {
            shuffleCards()
        }

        if (currentStep.value === 2) {
            dealCards()
        }

        if (currentStep.value === 3) {
            calculateWinner()
        }

        if (currentStep.value != maxStep) {
            currentStep.value = currentStep.value + 1
        } else {
            reset()
        }
    }

    const resetCards = () => {
        cards.value = getDefaultCards()
    }

    // Call this function when step = 1
    const shuffleCards = () => {
        cards.value = shuffle(cards.value)
    }

    // Call this function when step = 2
    const dealCards = () => {
        cards.value.forEach((card, index) => {
            players.value[index % maxPlayers].push(card)
        })
    }

    // Call this function when step = 3
    const calculateWinner = () => {
        let maxCount = 0
        // let winner = -1
        const ranks = players.value.map((player) => getCardRankCount(player))

        ranks.forEach((rankCount, playerIndex) => {
            const [highestRank, count] = getHighestRank(rankCount)

            if (
                count > maxCount ||
                (count === maxCount &&
                    isHigherRank(highestRank, ranks[winner.value] as any))
            ) {
                maxCount = count
                winner.value = playerIndex
            }
        })
    }

    // get card rank with count
    const getCardRankCount = (player: Player): Record<string, number> => {
        const rankCount: Record<string, number> = {}
        player.forEach((card) => {
            const rank = card[0]
            rankCount[rank] = (rankCount[rank] || 0) + 1
        })
        return rankCount
    }

    // Order by the highest rank with most card for single player
    const getHighestRank = (
        rankCount: Record<string, number>
    ): [string, number] => {
        return Object.entries(rankCount).reduce(
            ([highestRank, maxCount], [rank, count]) =>
                count > maxCount ||
                (count === maxCount && isHigherRank(rank, highestRank))
                    ? [rank, count]
                    : [highestRank, maxCount],
            ['', 0]
        )
    }

    // Check rank with two conditions
    const isHigherRank = (rank1: string, rank2: string): boolean => {
        const order = '23456789JQKA'
        return order.indexOf(rank1) > order.indexOf(rank2)
    }

    const reset = () => {
        currentStep.value = 1
        players.value = getDefaultPlayerCards()
        cards.value = getDefaultCards()
        winner.value = -1
        currentStep.value = 1
    }

    return {
        increaseStep,
        currentStep,
        cards,
        resetCards,
        shuffleCards,
        players,
        winner
    }
})
